package org.syntaxlisp.core.match.tree;

import org.syntaxlisp.core.utils.CommonUtils;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author HuangYijun
 * @data 2023-09-13 17:24
 **/
@Builder
@Data
public class NewCurPvt {

    private List<RepeatFrame> repeatStack;

    private MatchState curState;

    private NewMatchSeqNode curMatchNode;

    private int curOffset;

    private int nextOffset;

    private NewRefFrame belongsToWho;

    public List<RepeatFrame> getRepeatStack () {
        if (repeatStack == null) {
            repeatStack = new ArrayList<>();
        }
        return repeatStack;
    }

    public List<RepeatFrame> copyRepeatStack () {
        return repeatStack == null
                ? CommonUtils.asWritableList()
                : repeatStack.stream()
                             .map(RepeatFrame::copy)
                             .collect(Collectors.toList());
    }

    public boolean isReducing () {
        return nextOffset == NewMatchSeqNode.REDUCING;
    }

    public boolean isSameRepeat (NewCurPvt curPvt) {
        if (!CollectionUtils.isEmpty(curPvt.getRepeatStack())
                && !CollectionUtils.isEmpty(repeatStack)
                && curPvt.getRepeatStack().size() == repeatStack.size()) {
            for (int i = 0; i < repeatStack.size(); i ++) {
                if (!curPvt.getRepeatStack().get(i).equals(repeatStack.get(i))) {
                    return false;
                }
            }
            return true;
        } else {
            return CollectionUtils.isEmpty(curPvt.getRepeatStack())
                    && CollectionUtils.isEmpty(repeatStack);
        }
    }

    public boolean isRefPvt () {
        return curState.isRef();
    }

    public String getDef () {
        return belongsToWho.getDef();
    }

    public String requireRef () {
        return isRefPvt() ? curState.getSrc().getVal() : null;
    }

    public boolean equals (Object otherPvt) {
        if (!(otherPvt instanceof NewCurPvt )) {
            return false;
        }
        NewCurPvt ovt = (NewCurPvt) otherPvt;
        return ovt.getCurOffset() == curOffset
                && ovt.getNextOffset() == nextOffset
                && ovt.getCurState().equals(curState)
                && isSameRepeat(ovt);
    }

    public String toString() {
        return getDef() + "," + curOffset + "," + nextOffset;
    }
}
